/* -*- mode: c++ -*- */
#ifndef COMMON_H_
#define COMMON_H_
#define _ITERATOR_DEBUG_LEVEL 0

/* common.h - header file with information most files need.
 *
 * This should be included first by every .h and .c file.  That ensures
 * an opportunity to make early tweaks, such as is needed by Microsoft C++
 * for memory debugging.
 */
//#include "microsoft.h"  // should be first include in this file.

#include <algorithm>
#include <cassert>
#include <cstdarg>
#include <string>
#include <cstring>
#include <memory>
#include <vector>
#include <map>
#include <array>

#include "stdusing.h"

template<typename T>
using unique_ref = unique_ptr<T>const&;
using cache_ptr = unique_ptr<const char,void(*)(const char*)>;
inline void NullDeleter(const char*){}  // convenient for cache_ptr
inline void CacheDeleter(const char* S){free((void*)S);}


// define some annotations
#if     defined(_MSC_VER)
#   define  A_NORETURN  __declspec(noreturn)
#elif   defined(__GNUC__)
#   define  A_NORETURN  __attribute__((noreturn))
#else
#   define  A_NORETURN
#endif


#ifdef _MSC_VER
// if we let him check realloc, he'll make innumerable spurious complaints...
inline _Check_return_ void* r_i_p(void* ptr, size_t NewSize)
    {
    void*   Result = realloc(ptr, NewSize);
    __analysis_assume(Result != NULL);
    return Result;
    }
#else
#   define __analysis_assume
#   define r_i_p realloc
#endif

using       TOptionBag = std::map<string,string>;
class Global
    {
private:
    static vector<TOptionBag>   OptionStack;
    static int          GetIntArg(int Char, const char* Arg);
public:
    static void         ParseArgs(int ArgCount, const char* const* Args, bool Reset=false);
    friend void A_NORETURN Exit(int Line, int Error);
//    static const char*  GetOpt(const char* Name);
//    static bool         GetBoolOpt(const char* Name);
//    static int          GetIntOpt(const char* Name);
    static string       InputFilename() { return InputFile;     }

    static int          Dump;
    static string       ExpectCode;
    static int          ExpectLine;
    static string       InputFile;
    static string       Locale;
    static string       LocaleDir;
    static int          Verbose;
    };

void A_NORETURN ErrorExit(string Code, const char* Format, ...);
void ErrorPrologue(int Code);
void Usage(const char* Format, ...);


//#define MAX(a,b)    ((a) > (b) ? (a) : (b))
//#define MIN(a,b)    ((a) < (b) ? (a) : (b))

#define ARGUNUSED(x)    (void)(x)

#define MAX_OPERATOR_PATTERN    (32)

enum    ERRORCODE
    {
    ERROR_NONE                          = 0,
    ERROR_COMMANDLINE                   = 1,    /* error on commandline */
    ERROR_TERM_USED_AS_NONTERM          = 2,    /* */
    ERROR_UNDECL_LITERAL_IN_PROD        = 3,
    ERROR_MISSING_NAME_IN_TOKEN_DECL    = 4,
    ERROR_LITERAL_ALREADY_DEFINED       = 5,
    ERROR_UNDEFINED_OPERATOR            = 6,
    ERROR_EOF_IN_PREC                   = 7,
    ERROR_EXPECTING_OPERATOR_DECL       = 8,
    ERROR_PREC_WITHOUT_OPERATORS        = 9,
    ERROR_BAD_TOKEN_IN_DECL             = 10,
    ERROR_EXPECTING_NONTERM             = 11,
    ERROR_EXPECTING_COLON               = 12,
    ERROR_EXPECTING_AFTER_ACTION        = 13,
    ERROR_EXPECTING_OR_SEMI             = 14,
    ERROR_CANT_OPEN_INPUT_FILE          = 15,
    ERROR_INPUT_FILE_TOO_BIG            = 16,
    ERROR_UNKNOWN_FREAD_ERROR           = 17,
    ERROR_FREAD_FELL_SHORT              = 18,
    ERROR_UNDEFINED_NONTERM             = 19,
    ERROR_EOF_IN_COMMENT                = 20,
    ERROR_TERM_ALREADY_DEFINED          = 21,
    ERROR_EXPECTING_SEMICOLON           = 22,
    ERROR_LL_CONFLICT                   = 23,
    ERROR_UNREACHABLE_NONTERMINAL       = 24,
    ERROR_UNDECL_LITERAL_IN_OP_DECL     = 25,
    ERROR_DUPL_OP_DECL                  = 26,
    ERROR_OP_DECL_TOO_LONG              = 27,
    ERROR_DUP_SYM_IN_OPERATOR           = 28,
    ERROR_FAILED_OP_PREC_TABLE          = 29,
    ERROR_PREFIX_UNARY_DECL_LEFT        = 30,
    ERROR_POSTFIX_UNARY_DECL_RIGHT      = 31,
    ERROR_EOF_IN_TEST                   = 32,
    ERROR_UNDEF_SYMBOL_IN_TEST          = 33,
    ERROR_NONTERM_IN_TEST               = 34,
    ERROR_BAD_TOKEN_IN_TEST             = 35,
    ERROR_LEFT_RECURSION                = 36,
    ERROR_BAD_NAME_IN_TEMPLATE          = 37,
    ERROR_EXPECTING_IDENT_AFTER_START   = 38,
    ERROR_RULES_ARE_IDENTICAL           = 39,
    ERROR_COMMON_PREFIX_CONTAINS_ACTION = 40,
    ERROR_SYMBOL_DOES_NOT_TERMINATE     = 41,
    ERROR_A_NULLABLE_B_CLASH            = 42,
    ERROR_TWO_NULLABLE_RULES            = 43,
    ERROR_ILLEGAL_TOKEN                 = 44,
    ERROR_BAD_QUOTE                     = 45,
    ERROR_REDUCE_REDUCE_CONFLICT        = 46,
    ERROR_MUST_BE_NONASSOC              = 47,
    ERROR_NO_SYMBOL_BEFORE_SLASH        = 48,
    ERROR_NO_EMBEDDED_ACTION            = 49,
    ERROR_NOT_OPERATOR_OR_OPERAND       = 50,
    ERROR_NO_MATCHING_OPERATOR_PATTERN  = 51,
    ERROR_MISSING_OPERAND_IN_DECL       = 52,
    ERROR_BAD_OP_ABBREV                 = 53,
    ERROR_CLASH_IN_OP_ABBREV            = 54,
    ERROR_SUFFIXES_NULLABLE             = 55,
    ERROR_SUFFIXES_CLASH                = 56,
    };

void            ExitExpect(int LineNumber, int ErrorNumber);
void A_NORETURN Exit(int LineNumber, string ErrorName);
void            ErrorPrologue(int Error);
void A_NORETURN ErrorExit(int Error, const char* Format, ...);
//void A_NORETURN Error(const char* Format, ...);
void            ErrorEpilog(int Line);
void            Dump(const char* Format, ...);
void            DumpVerbose(const char* Format, ...);
void            Usage(const char* Format, ...);
//char*   StrClone(const char* Src);
//int     StrEndsWith(const char* Src, const char* Suffix);

//#define NEW(T)  ((T*)calloc(1, sizeof(T)))

#define ISALPHA(x)  isalpha((unsigned char)(x))
#define ISDIGIT(x)  isdigit((unsigned char)(x))

#define DUMP        if(Global::Dump)Dump
#define DUMPVERBOSE if(Global::Dump && Global::Verbose)Dump

#endif
